home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / xulrunner-1.9.0.14 / components / nsHelperAppDlg.js < prev    next >
Encoding:
Text File  |  2009-09-02  |  39.1 KB  |  1,009 lines

  1. /*
  2. //@line 44 "/build/buildd/xulrunner-1.9-1.9.0.14+build2+nobinonly/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  3. */
  4.  
  5. /* This file implements the nsIHelperAppLauncherDialog interface.
  6.  *
  7.  * The implementation consists of a JavaScript "class" named nsUnknownContentTypeDialog,
  8.  * comprised of:
  9.  *   - a JS constructor function
  10.  *   - a prototype providing all the interface methods and implementation stuff
  11.  *
  12.  * In addition, this file implements an nsIModule object that registers the
  13.  * nsUnknownContentTypeDialog component.
  14.  */
  15.  
  16. const PREF_BD_USEDOWNLOADDIR = "browser.download.useDownloadDir";
  17. const nsITimer = Components.interfaces.nsITimer;
  18.  
  19. /* ctor
  20.  */
  21. function nsUnknownContentTypeDialog() {
  22.     // Initialize data properties.
  23.     this.mLauncher = null;
  24.     this.mContext  = null;
  25.     this.mSourcePath = null;
  26.     this.chosenApp = null;
  27.     this.givenDefaultApp = false;
  28.     this.updateSelf = true;
  29.     this.mTitle    = "";
  30. }
  31.  
  32. nsUnknownContentTypeDialog.prototype = {
  33.     nsIMIMEInfo  : Components.interfaces.nsIMIMEInfo,
  34.  
  35.     QueryInterface: function (iid) {
  36.         if (!iid.equals(Components.interfaces.nsIHelperAppLauncherDialog) &&
  37.             !iid.equals(Components.interfaces.nsITimerCallback) &&
  38.             !iid.equals(Components.interfaces.nsISupports)) {
  39.             throw Components.results.NS_ERROR_NO_INTERFACE;
  40.         }
  41.         return this;
  42.     },
  43.  
  44.     // ---------- nsIHelperAppLauncherDialog methods ----------
  45.  
  46.     // show: Open XUL dialog using window watcher.  Since the dialog is not
  47.     //       modal, it needs to be a top level window and the way to open
  48.     //       one of those is via that route).
  49.     show: function(aLauncher, aContext, aReason)  {
  50.       this.mLauncher = aLauncher;
  51.       this.mContext  = aContext;
  52.  
  53.       const nsITimer = Components.interfaces.nsITimer;
  54.       this._showTimer = Components.classes["@mozilla.org/timer;1"]
  55.                                   .createInstance(nsITimer);
  56.       this._showTimer.initWithCallback(this, 0, nsITimer.TYPE_ONE_SHOT);
  57.     },
  58.  
  59.     // When opening from new tab, if tab closes while dialog is opening,
  60.     // (which is a race condition on the XUL file being cached and the timer
  61.     // in nsExternalHelperAppService), the dialog gets a blur and doesn't
  62.     // activate the OK button.  So we wait a bit before doing opening it.
  63.     reallyShow: function() {
  64.         try {
  65.           var ir = this.mContext.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  66.           var dwi = ir.getInterface(Components.interfaces.nsIDOMWindowInternal);
  67.           var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
  68.                              .getService(Components.interfaces.nsIWindowWatcher);
  69.           this.mDialog = ww.openWindow(dwi,
  70.                                        "chrome://mozapps/content/downloads/unknownContentType.xul",
  71.                                        null,
  72.                                        "chrome,centerscreen,titlebar,dialog=yes,dependent",
  73.                                        null);
  74.         } catch (ex) {
  75.           // The containing window may have gone away.  Break reference
  76.           // cycles and stop doing the download.
  77.           const NS_BINDING_ABORTED = 0x804b0002;
  78.           this.mLauncher.cancel(NS_BINDING_ABORTED);
  79.           return;
  80.         }
  81.  
  82.         // Hook this object to the dialog.
  83.         this.mDialog.dialog = this;
  84.  
  85.         // Hook up utility functions.
  86.         this.getSpecialFolderKey = this.mDialog.getSpecialFolderKey;
  87.  
  88.         // Watch for error notifications.
  89.         this.progressListener.helperAppDlg = this;
  90.         this.mLauncher.setWebProgressListener(this.progressListener);
  91.     },
  92.  
  93.     // promptForSaveToFile:  Display file picker dialog and return selected file.
  94.     //                       This is called by the External Helper App Service
  95.     //                       after the ucth dialog calls |saveToDisk| with a null
  96.     //                       target filename (no target, therefore user must pick).
  97.     //
  98.     //                       Alternatively, if the user has selected to have all
  99.     //                       files download to a specific location, return that
  100.     //                       location and don't ask via the dialog. 
  101.     //
  102.     // Note - this function is called without a dialog, so it cannot access any part
  103.     // of the dialog XUL as other functions on this object do. 
  104.     promptForSaveToFile: function(aLauncher, aContext, aDefaultFile, aSuggestedFileExtension, aForcePrompt) {
  105.       var result = null;
  106.       
  107.       this.mLauncher = aLauncher;
  108.  
  109.       let prefs = Components.classes["@mozilla.org/preferences-service;1"]
  110.                             .getService(Components.interfaces.nsIPrefBranch);
  111.  
  112.       if (!aForcePrompt) {
  113.         // Check to see if the user wishes to auto save to the default download
  114.         // folder without prompting. Note that preference might not be set.
  115.         let autodownload = false;
  116.         try {
  117.           autodownload = prefs.getBoolPref(PREF_BD_USEDOWNLOADDIR);
  118.         } catch (e) { }
  119.       
  120.         if (autodownload) {
  121.           // Retrieve the user's default download directory
  122.           let dnldMgr = Components.classes["@mozilla.org/download-manager;1"]
  123.                                   .getService(Components.interfaces.nsIDownloadManager);
  124.           let defaultFolder = dnldMgr.userDownloadsDirectory;
  125.           result = this.validateLeafName(defaultFolder, aDefaultFile, aSuggestedFileExtension);
  126.  
  127.           // Check to make sure we have a valid directory, otherwise, prompt
  128.           if (result)
  129.             return result;
  130.         }
  131.       }
  132.       
  133.       // Use file picker to show dialog.
  134.       var nsIFilePicker = Components.interfaces.nsIFilePicker;
  135.       var picker = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  136.  
  137.       var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService);
  138.       bundle = bundle.createBundle("chrome://mozapps/locale/downloads/unknownContentType.properties");
  139.  
  140.       var windowTitle = bundle.GetStringFromName("saveDialogTitle");
  141.       var parent = aContext.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowInternal);
  142.       picker.init(parent, windowTitle, nsIFilePicker.modeSave);
  143.       picker.defaultString = aDefaultFile;
  144.  
  145.       if (aSuggestedFileExtension) {
  146.         // aSuggestedFileExtension includes the period, so strip it
  147.         picker.defaultExtension = aSuggestedFileExtension.substring(1);
  148.       } 
  149.       else {
  150.         try {
  151.           picker.defaultExtension = this.mLauncher.MIMEInfo.primaryExtension;
  152.         } 
  153.         catch (ex) { }
  154.       }
  155.  
  156.       var wildCardExtension = "*";
  157.       if (aSuggestedFileExtension) {
  158.         wildCardExtension += aSuggestedFileExtension;
  159.         picker.appendFilter(this.mLauncher.MIMEInfo.description, wildCardExtension);
  160.       }
  161.  
  162.       picker.appendFilters( nsIFilePicker.filterAll );
  163.  
  164.       // Default to lastDir if it's valid, use the user's default
  165.       // downloads directory otherwise.
  166.       var dnldMgr = Components.classes["@mozilla.org/download-manager;1"]
  167.                               .getService(Components.interfaces.nsIDownloadManager);
  168.       try {
  169.         var lastDir = prefs.getComplexValue("browser.download.lastDir",
  170.                             Components.interfaces.nsILocalFile);
  171.         if (lastDir.exists())
  172.           picker.displayDirectory = lastDir;
  173.         else
  174.           picker.displayDirectory = dnldMgr.userDownloadsDirectory;
  175.       } catch (ex) {
  176.         picker.displayDirectory = dnldMgr.userDownloadsDirectory;
  177.       }
  178.  
  179.       if (picker.show() == nsIFilePicker.returnCancel) {
  180.         // null result means user cancelled.
  181.         return null;
  182.       }
  183.  
  184.       // Be sure to save the directory the user chose through the Save As... 
  185.       // dialog  as the new browser.download.dir since the old one
  186.       // didn't exist.
  187.       result = picker.file;
  188.  
  189.       if (result) {
  190.         try {
  191.           // Remove the file so that it's not there when we ensure non-existence later;
  192.           // this is safe because for the file to exist, the user would have had to
  193.           // confirm that he wanted the file overwritten.
  194.           if (result.exists())
  195.             result.remove(false);
  196.         }
  197.         catch (e) { }
  198.         var newDir = result.parent;
  199.         prefs.setComplexValue("browser.download.lastDir", Components.interfaces.nsILocalFile, newDir);
  200.         result = this.validateLeafName(newDir, result.leafName, null);
  201.       }
  202.       return result;
  203.     },
  204.  
  205.     /**
  206.      * Ensures that a local folder/file combination does not already exist in
  207.      * the file system (or finds such a combination with a reasonably similar
  208.      * leaf name), creates the corresponding file, and returns it.
  209.      *
  210.      * @param   aLocalFile
  211.      *          the folder where the file resides
  212.      * @param   aLeafName
  213.      *          the string name of the file (may be empty if no name is known,
  214.      *          in which case a name will be chosen)
  215.      * @param   aFileExt
  216.      *          the extension of the file, if one is known; this will be ignored
  217.      *          if aLeafName is non-empty
  218.      * @returns nsILocalFile
  219.      *          the created file
  220.      */
  221.     validateLeafName: function (aLocalFile, aLeafName, aFileExt)
  222.     {
  223.       if (!aLocalFile || !aLocalFile.exists())
  224.         return null;
  225.  
  226.       // Remove any leading periods, since we don't want to save hidden files
  227.       // automatically.
  228.       aLeafName = aLeafName.replace(/^\.+/, "");
  229.  
  230.       if (aLeafName == "")
  231.         aLeafName = "unnamed" + (aFileExt ? "." + aFileExt : "");
  232.       aLocalFile.append(aLeafName);
  233.  
  234.       this.makeFileUnique(aLocalFile);
  235.  
  236. //@line 296 "/build/buildd/xulrunner-1.9-1.9.0.14+build2+nobinonly/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  237.  
  238.       return aLocalFile;
  239.     },
  240.  
  241.     /**
  242.      * Generates and returns a uniquely-named file from aLocalFile.  If
  243.      * aLocalFile does not exist, it will be the file returned; otherwise, a
  244.      * file whose name is similar to that of aLocalFile will be returned.
  245.      */
  246.     makeFileUnique: function (aLocalFile)
  247.     {
  248.       try {
  249.         // Note - this code is identical to that in 
  250.         //   toolkit/content/contentAreaUtils.js.
  251.         // If you are updating this code, update that code too! We can't share code
  252.         // here since this is called in a js component. 
  253.         var collisionCount = 0;
  254.         while (aLocalFile.exists()) {
  255.           collisionCount++;
  256.           if (collisionCount == 1) {
  257.             // Append "(2)" before the last dot in (or at the end of) the filename
  258.             // special case .ext.gz etc files so we don't wind up with .tar(2).gz
  259.             if (aLocalFile.leafName.match(/\.[^\.]{1,3}\.(gz|bz2|Z)$/i)) {
  260.               aLocalFile.leafName = aLocalFile.leafName.replace(/\.[^\.]{1,3}\.(gz|bz2|Z)$/i, "(2)$&");
  261.             }
  262.             else {
  263.               aLocalFile.leafName = aLocalFile.leafName.replace(/(\.[^\.]*)?$/, "(2)$&");
  264.             }
  265.           }
  266.           else {
  267.             // replace the last (n) in the filename with (n+1)
  268.             aLocalFile.leafName = aLocalFile.leafName.replace(/^(.*\()\d+\)/, "$1" + (collisionCount+1) + ")");
  269.           }
  270.         }
  271.         aLocalFile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600);
  272.       }
  273.       catch (e) {
  274.         dump("*** exception in validateLeafName: " + e + "\n");
  275.         if (aLocalFile.leafName == "" || aLocalFile.isDirectory()) {
  276.           aLocalFile.append("unnamed");
  277.           if (aLocalFile.exists())
  278.             aLocalFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600);
  279.         }
  280.       }
  281.     },
  282.     
  283.     // ---------- implementation methods ----------
  284.  
  285.     // Web progress listener so we can detect errors while mLauncher is
  286.     // streaming the data to a temporary file.
  287.     progressListener: {
  288.         // Implementation properties.
  289.         helperAppDlg: null,
  290.  
  291.         // nsIWebProgressListener methods.
  292.         // Look for error notifications and display alert to user.
  293.         onStatusChange: function( aWebProgress, aRequest, aStatus, aMessage ) {
  294.             if ( aStatus != Components.results.NS_OK ) {
  295.                 // Get prompt service.
  296.                 var prompter = Components.classes[ "@mozilla.org/embedcomp/prompt-service;1" ]
  297.                                    .getService( Components.interfaces.nsIPromptService );
  298.                 // Display error alert (using text supplied by back-end).
  299.                 prompter.alert( this.dialog, this.helperAppDlg.mTitle, aMessage );
  300.  
  301.                 // Close the dialog.
  302.                 this.helperAppDlg.onCancel();
  303.                 if ( this.helperAppDlg.mDialog ) {
  304.                     this.helperAppDlg.mDialog.close();
  305.                 }
  306.             }
  307.         },
  308.  
  309.         // Ignore onProgressChange, onProgressChange64, onStateChange, onLocationChange, onSecurityChange, and onRefreshAttempted notifications.
  310.         onProgressChange: function( aWebProgress,
  311.                                     aRequest,
  312.                                     aCurSelfProgress,
  313.                                     aMaxSelfProgress,
  314.                                     aCurTotalProgress,
  315.                                     aMaxTotalProgress ) {
  316.         },
  317.  
  318.         onProgressChange64: function( aWebProgress,
  319.                                       aRequest,
  320.                                       aCurSelfProgress,
  321.                                       aMaxSelfProgress,
  322.                                       aCurTotalProgress,
  323.                                       aMaxTotalProgress ) {
  324.         },
  325.  
  326.  
  327.  
  328.         onStateChange: function( aWebProgress, aRequest, aStateFlags, aStatus ) {
  329.         },
  330.  
  331.         onLocationChange: function( aWebProgress, aRequest, aLocation ) {
  332.         },
  333.  
  334.         onSecurityChange: function( aWebProgress, aRequest, state ) {
  335.         },
  336.  
  337.         onRefreshAttempted: function( aWebProgress, aURI, aDelay, aSameURI ) {
  338.           return true;
  339.     }
  340.     },
  341.  
  342.     // initDialog:  Fill various dialog fields with initial content.
  343.     initDialog : function() {
  344.       // Put file name in window title.
  345.       var suggestedFileName = this.mLauncher.suggestedFileName;
  346.  
  347.       // Some URIs do not implement nsIURL, so we can't just QI.
  348.       var url   = this.mLauncher.source;
  349.       var fname = "";
  350.       this.mSourcePath = url.prePath;
  351.       try {
  352.           url = url.QueryInterface( Components.interfaces.nsIURL );
  353.           // A url, use file name from it.
  354.           fname = url.fileName;
  355.           this.mSourcePath += url.directory;
  356.       } catch (ex) {
  357.           // A generic uri, use path.
  358.           fname = url.path;
  359.           this.mSourcePath += url.path;
  360.       }
  361.  
  362.       if (suggestedFileName)
  363.         fname = suggestedFileName;
  364.       
  365.       var displayName = fname.replace(/ +/g, " ");
  366.  
  367.       this.mTitle = this.dialogElement("strings").getFormattedString("title", [displayName]);
  368.       this.mDialog.document.title = this.mTitle;
  369.  
  370.       // Put content type, filename and location into intro.
  371.       this.initIntro(url, fname, displayName);
  372.  
  373.       var iconString = "moz-icon://" + fname + "?size=16&contentType=" + this.mLauncher.MIMEInfo.MIMEType;
  374.       this.dialogElement("contentTypeImage").setAttribute("src", iconString);
  375.  
  376.       // if always-save and is-executable and no-handler
  377.       // then set up simple ui
  378.       var mimeType = this.mLauncher.MIMEInfo.MIMEType;
  379.       var shouldntRememberChoice = (mimeType == "application/octet-stream" || 
  380.                                     mimeType == "application/x-msdownload" ||
  381.                                     this.mLauncher.targetFileIsExecutable);
  382.       if (shouldntRememberChoice && !this.openWithDefaultOK()) {
  383.         // hide featured choice 
  384.         this.dialogElement("normalBox").collapsed = true;
  385.         // show basic choice 
  386.         this.dialogElement("basicBox").collapsed = false;
  387.         // change button labels
  388.         this.mDialog.document.documentElement.getButton("accept").label = this.dialogElement("strings").getString("unknownAccept.label");
  389.         this.mDialog.document.documentElement.getButton("cancel").label = this.dialogElement("strings").getString("unknownCancel.label");
  390.         // hide other handler
  391.         this.dialogElement("openHandler").collapsed = true;
  392.         // set save as the selected option
  393.         this.dialogElement("mode").selectedItem = this.dialogElement("save");
  394.       }
  395.       else {
  396.         this.initAppAndSaveToDiskValues();
  397.  
  398.         // Initialize "always ask me" box. This should always be disabled
  399.         // and set to true for the ambiguous type application/octet-stream.
  400.         // We don't also check for application/x-msdownload here since we
  401.         // want users to be able to autodownload .exe files. 
  402.         var rememberChoice = this.dialogElement("rememberChoice");
  403.  
  404. //@line 482 "/build/buildd/xulrunner-1.9-1.9.0.14+build2+nobinonly/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  405.         if (shouldntRememberChoice) {
  406.           rememberChoice.checked = false;
  407.           rememberChoice.disabled = true;
  408.         }
  409.         else {
  410.           rememberChoice.checked = !this.mLauncher.MIMEInfo.alwaysAskBeforeHandling;
  411.         }
  412.         this.toggleRememberChoice(rememberChoice);
  413.  
  414.         // XXXben - menulist won't init properly, hack. 
  415.         var openHandler = this.dialogElement("openHandler");
  416.         openHandler.parentNode.removeChild(openHandler);
  417.         var openHandlerBox = this.dialogElement("openHandlerBox");
  418.         openHandlerBox.appendChild(openHandler);
  419.       }
  420.  
  421.       this.mDialog.setTimeout("dialog.postShowCallback()", 0);
  422.       
  423.       this.mDialog.document.documentElement.getButton("accept").disabled = true;
  424.       this._showTimer = Components.classes["@mozilla.org/timer;1"]
  425.                                   .createInstance(nsITimer);
  426.       this._showTimer.initWithCallback(this, 250, nsITimer.TYPE_ONE_SHOT);
  427.     },
  428.  
  429.     notify: function (aTimer) {
  430.       if (aTimer == this._showTimer) {
  431.         if (!this.mDialog) {
  432.           this.reallyShow();
  433.         } else {
  434.           // The user may have already canceled the dialog.
  435.           try {
  436.             if (!this._blurred) {
  437.               this.mDialog.document.documentElement.getButton("accept").disabled = false;
  438.             }
  439.           } catch (ex) {}
  440.           this._delayExpired = true;
  441.         }
  442.         // The timer won't release us, so we have to release it.
  443.         this._showTimer = null;
  444.       }
  445.       else if (aTimer == this._saveToDiskTimer) {
  446.         // Since saveToDisk may open a file picker and therefore block this routine,
  447.         // we should only call it once the dialog is closed.
  448.         this.mLauncher.saveToDisk(null, false);
  449.         this._saveToDiskTimer = null;
  450.       }
  451.     },
  452.  
  453.     postShowCallback: function () {
  454.       this.mDialog.sizeToContent();
  455.  
  456.       // Set initial focus
  457.       this.dialogElement("mode").focus();
  458.     },
  459.  
  460.     // initIntro:
  461.     initIntro: function(url, filename, displayname) {
  462.         this.dialogElement( "location" ).value = displayname;
  463.         this.dialogElement( "location" ).setAttribute("realname", filename);
  464.         this.dialogElement( "location" ).setAttribute("tooltiptext", displayname);
  465.  
  466.         // if mSourcePath is a local file, then let's use the pretty path name instead of an ugly
  467.         // url...
  468.         var pathString = this.mSourcePath;
  469.         try 
  470.         {
  471.           var fileURL = url.QueryInterface(Components.interfaces.nsIFileURL);
  472.           if (fileURL)
  473.           {
  474.             var fileObject = fileURL.file;
  475.             if (fileObject)
  476.             {
  477.               var parentObject = fileObject.parent;
  478.               if (parentObject)
  479.               {
  480.                 pathString = parentObject.path;
  481.               }
  482.             }
  483.           }
  484.         } catch(ex) {}
  485.  
  486.         if (pathString == this.mSourcePath)
  487.         {
  488.           // wasn't a fileURL
  489.           var tmpurl = url.clone(); // don't want to change the real url
  490.           try {
  491.             tmpurl.userPass = "";
  492.           } catch (ex) {}
  493.           pathString = tmpurl.prePath;
  494.         }
  495.  
  496.         // Set the location text, which is separate from the intro text so it can be cropped
  497.         var location = this.dialogElement( "source" );
  498.         location.value = pathString;
  499.         location.setAttribute("tooltiptext", this.mSourcePath);
  500.         
  501.         // Show the type of file. 
  502.         var type = this.dialogElement("type");
  503.         var mimeInfo = this.mLauncher.MIMEInfo;
  504.         
  505.         // 1. Try to use the pretty description of the type, if one is available.
  506.         var typeString = mimeInfo.description;
  507.         
  508.         if (typeString == "") {
  509.           // 2. If there is none, use the extension to identify the file, e.g. "ZIP file"
  510.           var primaryExtension = "";
  511.           try {
  512.             primaryExtension = mimeInfo.primaryExtension;
  513.           }
  514.           catch (ex) {
  515.           }
  516.           if (primaryExtension != "")
  517.             typeString = this.dialogElement("strings").getFormattedString("fileType", [primaryExtension.toUpperCase()]);
  518.           // 3. If we can't even do that, just give up and show the MIME type. 
  519.           else
  520.             typeString = mimeInfo.MIMEType;
  521.         }
  522.         
  523.         type.value = typeString;
  524.     },
  525.     
  526.     _blurred: false,
  527.     _delayExpired: false, 
  528.     onBlur: function(aEvent) {
  529.       this._blurred = true;
  530.       this.mDialog.document.documentElement.getButton("accept").disabled = true;
  531.     },
  532.     
  533.     onFocus: function(aEvent) {
  534.       this._blurred = false;
  535.       if (this._delayExpired) {
  536.         var script = "document.documentElement.getButton('accept').disabled = false";
  537.         this.mDialog.setTimeout(script, 250);
  538.       }
  539.     },
  540.  
  541.     // Returns true if opening the default application makes sense.
  542.     openWithDefaultOK: function() {
  543.         // The checking is different on Windows...
  544. //@line 632 "/build/buildd/xulrunner-1.9-1.9.0.14+build2+nobinonly/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  545.             // On other platforms, default is Ok if there is a default app.
  546.             // Note that nsIMIMEInfo providers need to ensure that this holds true
  547.             // on each platform.
  548.         return this.mLauncher.MIMEInfo.hasDefaultHandler;
  549. //@line 637 "/build/buildd/xulrunner-1.9-1.9.0.14+build2+nobinonly/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  550.     },
  551.     
  552.     // Set "default" application description field.
  553.     initDefaultApp: function() {
  554.       // Use description, if we can get one.
  555.       var desc = this.mLauncher.MIMEInfo.defaultDescription;
  556.       if (desc) {
  557.         var defaultApp = this.dialogElement("strings").getFormattedString("defaultApp", [desc]);
  558.         this.dialogElement("defaultHandler").label = defaultApp;
  559.       }
  560.       else {
  561.         this.dialogElement("modeDeck").setAttribute("selectedIndex", "1");
  562.         // Hide the default handler item too, in case the user picks a 
  563.         // custom handler at a later date which triggers the menulist to show.
  564.         this.dialogElement("defaultHandler").hidden = true;
  565.       }
  566.     },
  567.  
  568.     // getPath:
  569.     getPath: function (aFile) {
  570. //@line 660 "/build/buildd/xulrunner-1.9-1.9.0.14+build2+nobinonly/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  571.       return aFile.path;
  572. //@line 662 "/build/buildd/xulrunner-1.9-1.9.0.14+build2+nobinonly/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  573.     },
  574.  
  575.     // initAppAndSaveToDiskValues:
  576.     initAppAndSaveToDiskValues: function() {
  577.       var modeGroup = this.dialogElement("mode");
  578.  
  579.       // We don't let users open .exe files or random binary data directly 
  580.       // from the browser at the moment because of security concerns. 
  581.       var openWithDefaultOK = this.openWithDefaultOK();
  582.       var mimeType = this.mLauncher.MIMEInfo.MIMEType;
  583.       if (this.mLauncher.targetFileIsExecutable || (
  584.           (mimeType == "application/octet-stream" ||
  585.            mimeType == "application/x-msdownload") && 
  586.            !openWithDefaultOK)) {
  587.         this.dialogElement("open").disabled = true;
  588.         var openHandler = this.dialogElement("openHandler");
  589.         openHandler.disabled = true;
  590.         openHandler.selectedItem = null;
  591.         modeGroup.selectedItem = this.dialogElement("save");
  592.         return;
  593.       }
  594.     
  595.       // Fill in helper app info, if there is any.
  596.       try {
  597.         this.chosenApp =
  598.           this.mLauncher.MIMEInfo.preferredApplicationHandler
  599.               .QueryInterface(Components.interfaces.nsILocalHandlerApp);
  600.       } catch (e) {
  601.         this.chosenApp = null;
  602.       }
  603.       // Initialize "default application" field.
  604.       this.initDefaultApp();
  605.  
  606.       var otherHandler = this.dialogElement("otherHandler");
  607.               
  608.       // Fill application name textbox.
  609.       if (this.chosenApp && this.chosenApp.executable && 
  610.           this.chosenApp.executable.path) {
  611.         otherHandler.setAttribute("path",
  612.                                   this.getPath(this.chosenApp.executable));
  613.         otherHandler.label = this.chosenApp.executable.leafName;
  614.         otherHandler.hidden = false;
  615.       }
  616.  
  617.       var useDefault = this.dialogElement("useSystemDefault");
  618.       var openHandler = this.dialogElement("openHandler");
  619.       openHandler.selectedIndex = 0;
  620.  
  621.       if (this.mLauncher.MIMEInfo.preferredAction == this.nsIMIMEInfo.useSystemDefault) {
  622.         // Open (using system default).
  623.         modeGroup.selectedItem = this.dialogElement("open");
  624.       } else if (this.mLauncher.MIMEInfo.preferredAction == this.nsIMIMEInfo.useHelperApp) {
  625.         // Open with given helper app.
  626.         modeGroup.selectedItem = this.dialogElement("open");
  627.         openHandler.selectedIndex = 1;
  628.       } else {
  629.         // Save to disk.
  630.         modeGroup.selectedItem = this.dialogElement("save");
  631.       }
  632.       
  633.       // If we don't have a "default app" then disable that choice.
  634.       if (!openWithDefaultOK) {
  635.         var useDefault = this.dialogElement("defaultHandler");
  636.         var isSelected = useDefault.selected;
  637.         
  638.         // Disable that choice.
  639.         useDefault.hidden = true;
  640.         // If that's the default, then switch to "save to disk."
  641.         if (isSelected) {
  642.           openHandler.selectedIndex = 1;
  643.           modeGroup.selectedItem = this.dialogElement("save");
  644.         }
  645.       }
  646.       
  647.       otherHandler.nextSibling.hidden = otherHandler.nextSibling.nextSibling.hidden = false;
  648.       this.updateOKButton();
  649.     },
  650.  
  651.     // Returns the user-selected application
  652.     helperAppChoice: function() {
  653.       return this.chosenApp;
  654.     },
  655.     
  656.     get saveToDisk() {
  657.       return this.dialogElement("save").selected;
  658.     },
  659.     
  660.     get useOtherHandler() {
  661.       return this.dialogElement("open").selected && this.dialogElement("openHandler").selectedIndex == 1;
  662.     },
  663.     
  664.     get useSystemDefault() {
  665.       return this.dialogElement("open").selected && this.dialogElement("openHandler").selectedIndex == 0;
  666.     },
  667.     
  668.     toggleRememberChoice: function (aCheckbox) {
  669.         this.dialogElement("settingsChange").hidden = !aCheckbox.checked;
  670.         this.mDialog.sizeToContent();
  671.     },
  672.     
  673.     openHandlerCommand: function () {
  674.       var openHandler = this.dialogElement("openHandler");
  675.       if (openHandler.selectedItem.id == "choose")
  676.         this.chooseApp();
  677.       else
  678.         openHandler.setAttribute("lastSelectedItemID", openHandler.selectedItem.id);
  679.     },
  680.  
  681.     updateOKButton: function() {
  682.       var ok = false;
  683.       if (this.dialogElement("save").selected) {
  684.         // This is always OK.
  685.         ok = true;
  686.       } 
  687.       else if (this.dialogElement("open").selected) {
  688.         switch (this.dialogElement("openHandler").selectedIndex) {
  689.         case 0:
  690.           // No app need be specified in this case.
  691.           ok = true;
  692.           break;
  693.         case 1:
  694.           // only enable the OK button if we have a default app to use or if 
  695.           // the user chose an app....
  696.           ok = this.chosenApp || /\S/.test(this.dialogElement("otherHandler").getAttribute("path")); 
  697.         break;
  698.         }
  699.       }
  700.  
  701.       // Enable Ok button if ok to press.
  702.       this.mDialog.document.documentElement.getButton("accept").disabled = !ok;
  703.     },
  704.     
  705.     // Returns true iff the user-specified helper app has been modified.
  706.     appChanged: function() {
  707.       return this.helperAppChoice() != this.mLauncher.MIMEInfo.preferredApplicationHandler;
  708.     },
  709.  
  710.     updateMIMEInfo: function() {
  711.       var needUpdate = false;
  712.       // If current selection differs from what's in the mime info object,
  713.       // then we need to update.
  714.       if (this.saveToDisk) {
  715.         needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.saveToDisk;
  716.         if (needUpdate)
  717.           this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.saveToDisk;
  718.       } 
  719.       else if (this.useSystemDefault) {
  720.         needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.useSystemDefault;
  721.         if (needUpdate)
  722.           this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.useSystemDefault;
  723.       } 
  724.       else {
  725.         // For "open with", we need to check both preferred action and whether the user chose
  726.         // a new app.
  727.         needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.useHelperApp || this.appChanged();
  728.         if (needUpdate) {
  729.           this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.useHelperApp;
  730.           // App may have changed - Update application
  731.           var app = this.helperAppChoice();
  732.           this.mLauncher.MIMEInfo.preferredApplicationHandler = app;
  733.         }
  734.       }
  735.       // We will also need to update if the "always ask" flag has changed.
  736.       needUpdate = needUpdate || this.mLauncher.MIMEInfo.alwaysAskBeforeHandling != (!this.dialogElement("rememberChoice").checked);
  737.  
  738.       // One last special case: If the input "always ask" flag was false, then we always
  739.       // update.  In that case we are displaying the helper app dialog for the first
  740.       // time for this mime type and we need to store the user's action in the mimeTypes.rdf
  741.       // data source (whether that action has changed or not; if it didn't change, then we need
  742.       // to store the "always ask" flag so the helper app dialog will or won't display
  743.       // next time, per the user's selection).
  744.       needUpdate = needUpdate || !this.mLauncher.MIMEInfo.alwaysAskBeforeHandling;
  745.  
  746.       // Make sure mime info has updated setting for the "always ask" flag.
  747.       this.mLauncher.MIMEInfo.alwaysAskBeforeHandling = !this.dialogElement("rememberChoice").checked;
  748.  
  749.       return needUpdate;        
  750.     },
  751.     
  752.     // See if the user changed things, and if so, update the
  753.     // mimeTypes.rdf entry for this mime type.
  754.     updateHelperAppPref: function() {
  755.       var ha = new this.mDialog.HelperApps();
  756.       ha.updateTypeInfo(this.mLauncher.MIMEInfo);
  757.       ha.destroy();
  758.     },
  759.     
  760.     // onOK:
  761.     onOK: function() {
  762.       // Verify typed app path, if necessary.
  763.       if (this.useOtherHandler) {
  764.         var helperApp = this.helperAppChoice();
  765.         if (!helperApp || !helperApp.executable ||
  766.             !helperApp.executable.exists()) {
  767.           // Show alert and try again.        
  768.           var bundle = this.dialogElement("strings");                    
  769.           var msg = bundle.getFormattedString("badApp", [this.dialogElement("otherHandler").path]);
  770.           var svc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
  771.           svc.alert(this.mDialog, bundle.getString("badApp.title"), msg);
  772.  
  773.           // Disable the OK button.
  774.           this.mDialog.document.documentElement.getButton("accept").disabled = true;
  775.           this.dialogElement("mode").focus();          
  776.  
  777.           // Clear chosen application.
  778.           this.chosenApp = null;
  779.  
  780.           // Leave dialog up.
  781.           return false;
  782.         }
  783.       }
  784.         
  785.       // Remove our web progress listener (a progress dialog will be
  786.       // taking over).
  787.       this.mLauncher.setWebProgressListener(null);
  788.  
  789.       // saveToDisk and launchWithApplication can return errors in 
  790.       // certain circumstances (e.g. The user clicks cancel in the
  791.       // "Save to Disk" dialog. In those cases, we don't want to
  792.       // update the helper application preferences in the RDF file.
  793.       try {
  794.         var needUpdate = this.updateMIMEInfo();
  795.         
  796.         if (this.dialogElement("save").selected) {
  797.           // If we're using a default download location, create a path
  798.           // for the file to be saved to to pass to |saveToDisk| - otherwise
  799.           // we must ask the user to pick a save name.
  800.  
  801. //@line 904 "/build/buildd/xulrunner-1.9-1.9.0.14+build2+nobinonly/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  802.  
  803.           // see @notify
  804.           // we cannot use opener's setTimeout, see bug 420405
  805.           this._saveToDiskTimer = Components.classes["@mozilla.org/timer;1"]
  806.                                             .createInstance(nsITimer);
  807.           this._saveToDiskTimer.initWithCallback(this, 0,
  808.                                                  nsITimer.TYPE_ONE_SHOT);
  809.         }
  810.         else
  811.           this.mLauncher.launchWithApplication(null, false);
  812.  
  813.         // Update user pref for this mime type (if necessary). We do not
  814.         // store anything in the mime type preferences for the ambiguous
  815.         // type application/octet-stream. We do NOT do this for 
  816.         // application/x-msdownload since we want users to be able to 
  817.         // autodownload these to disk. 
  818.         if (needUpdate && this.mLauncher.MIMEInfo.MIMEType != "application/octet-stream")
  819.           this.updateHelperAppPref();
  820.       } catch(e) { }
  821.  
  822.       // Unhook dialog from this object.
  823.       this.mDialog.dialog = null;
  824.  
  825.       // Close up dialog by returning true.
  826.       return true;
  827.     },
  828.  
  829.     // onCancel:
  830.     onCancel: function() {
  831.       // Remove our web progress listener.
  832.       this.mLauncher.setWebProgressListener(null);
  833.  
  834.       // Cancel app launcher.
  835.       try {
  836.         const NS_BINDING_ABORTED = 0x804b0002;
  837.         this.mLauncher.cancel(NS_BINDING_ABORTED);
  838.       } catch(exception) {
  839.       }
  840.  
  841.       // Unhook dialog from this object.
  842.       this.mDialog.dialog = null;
  843.  
  844.       // Close up dialog by returning true.
  845.       return true;
  846.     },
  847.  
  848.     // dialogElement:  Convenience. 
  849.     dialogElement: function(id) {
  850.       return this.mDialog.document.getElementById(id);
  851.     },
  852.  
  853.     // Retrieve the pretty description from the file
  854.     getFileDisplayName: function getFileDisplayName(file)
  855.     { 
  856. //@line 966 "/build/buildd/xulrunner-1.9-1.9.0.14+build2+nobinonly/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  857.         return file.leafName;
  858.     },
  859.  
  860.     // chooseApp:  Open file picker and prompt user for application.
  861.     chooseApp: function() {
  862. //@line 1037 "/build/buildd/xulrunner-1.9-1.9.0.14+build2+nobinonly/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  863.       var nsIFilePicker = Components.interfaces.nsIFilePicker;
  864.       var fp = Components.classes["@mozilla.org/filepicker;1"]
  865.                          .createInstance(nsIFilePicker);
  866.       fp.init(this.mDialog,
  867.               this.dialogElement("strings").getString("chooseAppFilePickerTitle"),
  868.               nsIFilePicker.modeOpen);
  869.  
  870.       fp.appendFilters(nsIFilePicker.filterApps);
  871.  
  872.       if (fp.show() == nsIFilePicker.returnOK && fp.file) {
  873.         // Show the "handler" menulist since we have a (user-specified) 
  874.         // application now.
  875.         this.dialogElement("modeDeck").setAttribute("selectedIndex", "0");
  876.         
  877.         // Remember the file they chose to run.
  878.         var localHandlerApp = 
  879.           Components.classes["@mozilla.org/uriloader/local-handler-app;1"].
  880.           createInstance(Components.interfaces.nsILocalHandlerApp);
  881.         localHandlerApp.executable = fp.file;
  882.         this.chosenApp = localHandlerApp;
  883.         
  884.         // Update dialog.
  885.         var otherHandler = this.dialogElement("otherHandler");
  886.         otherHandler.removeAttribute("hidden");
  887.         otherHandler.setAttribute("path", this.getPath(this.chosenApp.executable));
  888.         otherHandler.label = this.chosenApp.executable.leafName;
  889.         this.dialogElement("openHandler").selectedIndex = 1;
  890.         this.dialogElement("openHandler").setAttribute("lastSelectedItemID", "otherHandler");
  891.         
  892.         this.dialogElement("mode").selectedItem = this.dialogElement("open");
  893.       }
  894.       else {
  895.         var openHandler = this.dialogElement("openHandler");
  896.         var lastSelectedID = openHandler.getAttribute("lastSelectedItemID");
  897.         if (!lastSelectedID)
  898.           lastSelectedID = "defaultHandler";
  899.         openHandler.selectedItem = this.dialogElement(lastSelectedID);
  900.       }
  901. //@line 1076 "/build/buildd/xulrunner-1.9-1.9.0.14+build2+nobinonly/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  902.     },
  903.  
  904.     // Turn this on to get debugging messages.
  905.     debug: false,
  906.  
  907.     // Dump text (if debug is on).
  908.     dump: function( text ) {
  909.         if ( this.debug ) {
  910.             dump( text ); 
  911.         }
  912.     },
  913.  
  914.     // dumpInfo:
  915.     doDebug: function() {
  916.         const nsIProgressDialog = Components.interfaces.nsIProgressDialog;
  917.         // Open new progress dialog.
  918.         var progress = Components.classes[ "@mozilla.org/progressdialog;1" ]
  919.                          .createInstance( nsIProgressDialog );
  920.         // Show it.
  921.         progress.open( this.mDialog );
  922.     },
  923.  
  924.     // dumpObj:
  925.     dumpObj: function( spec ) {
  926.          var val = "<undefined>";
  927.          try {
  928.              val = eval( "this."+spec ).toString();
  929.          } catch( exception ) {
  930.          }
  931.          this.dump( spec + "=" + val + "\n" );
  932.     },
  933.  
  934.     // dumpObjectProperties
  935.     dumpObjectProperties: function( desc, obj ) {
  936.          for( prop in obj ) {
  937.              this.dump( desc + "." + prop + "=" );
  938.              var val = "<undefined>";
  939.              try {
  940.                  val = obj[ prop ];
  941.              } catch ( exception ) {
  942.              }
  943.              this.dump( val + "\n" );
  944.          }
  945.     }
  946. }
  947.  
  948. // This Component's module implementation.  All the code below is used to get this
  949. // component registered and accessible via XPCOM.
  950. var module = {
  951.     firstTime: true,
  952.  
  953.     // registerSelf: Register this component.
  954.     registerSelf: function (compMgr, fileSpec, location, type) {
  955.         if (this.firstTime) {
  956.             this.firstTime = false;
  957.             throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
  958.         }
  959.         compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  960.  
  961.         compMgr.registerFactoryLocation( this.cid,
  962.                                          "Unknown Content Type Dialog",
  963.                                          this.contractId,
  964.                                          fileSpec,
  965.                                          location,
  966.                                          type );
  967.     },
  968.  
  969.     // getClassObject: Return this component's factory object.
  970.     getClassObject: function (compMgr, cid, iid) {
  971.         if (!cid.equals(this.cid)) {
  972.             throw Components.results.NS_ERROR_NO_INTERFACE;
  973.         }
  974.  
  975.         if (!iid.equals(Components.interfaces.nsIFactory)) {
  976.             throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  977.         }
  978.  
  979.         return this.factory;
  980.     },
  981.  
  982.     /* CID for this class */
  983.     cid: Components.ID("{F68578EB-6EC2-4169-AE19-8C6243F0ABE1}"),
  984.  
  985.     /* Contract ID for this class */
  986.     contractId: "@mozilla.org/helperapplauncherdialog;1",
  987.  
  988.     /* factory object */
  989.     factory: {
  990.         // createInstance: Return a new nsProgressDialog object.
  991.         createInstance: function (outer, iid) {
  992.             if (outer != null)
  993.                 throw Components.results.NS_ERROR_NO_AGGREGATION;
  994.  
  995.             return (new nsUnknownContentTypeDialog()).QueryInterface(iid);
  996.         }
  997.     },
  998.  
  999.     // canUnload: n/a (returns true)
  1000.     canUnload: function(compMgr) {
  1001.         return true;
  1002.     }
  1003. };
  1004.  
  1005. // NSGetModule: Return the nsIModule object.
  1006. function NSGetModule(compMgr, fileSpec) {
  1007.     return module;
  1008. }
  1009.